//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package short_note_api_serv

import (
	"context"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_doc_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/short_note_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/short_note_api"
	"go.mongodb.org/mongo-driver/mongo"
)

type ShortNoteApiImpl struct {
	short_note_api.UnimplementedShortNoteApiServer
}

func (apiImpl *ShortNoteApiImpl) Add(ctx context.Context, req *short_note_api.AddRequest) (*short_note_api.AddResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &short_note_api.AddResponse{
			Code:   short_note_api.AddResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &short_note_api.AddResponse{
			Code:   short_note_api.AddResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &short_note_api.AddResponse{
			Code:   short_note_api.AddResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	//check target exist
	if req.ShortNoteType == short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_TASK || req.ShortNoteType == short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_BUG {
		exist, err := issue_dao.IssueDao.Exist(ctx, req.ProjectId, req.TargetId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &short_note_api.AddResponse{
				Code:   short_note_api.AddResponse_CODE_NO_TARGET,
				ErrMsg: "相关工单不存在",
			}, nil
		}
	} else if req.ShortNoteType == short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_DOC {
		exist, err := project_doc_dao.DocContentDao.Exist(ctx, req.TargetId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &short_note_api.AddResponse{
				Code:   short_note_api.AddResponse_CODE_NO_TARGET,
				ErrMsg: "相关文档不存在",
			}, nil
		}
	}

	exist, err := short_note_dao.ShortNoteDao.Exist(ctx, sessionItem.UserId, req.ProjectId, uint32(req.ShortNoteType), req.TargetId)
	if err != nil {
		return nil, err
	}
	if exist {
		return &short_note_api.AddResponse{
			Code: short_note_api.AddResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {

		err = short_note_dao.ShortNoteDao.Insert(sessCtx, &short_note_dao.ShortNoteDbItem{
			UserId:        sessionItem.UserId,
			ProjectId:     req.ProjectId,
			ShortNoteType: uint32(req.ShortNoteType),
			TargetId:      req.TargetId,
		})
		if err != nil {
			return nil, err
		}
		return &short_note_api.AddResponse{
			Code: short_note_api.AddResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateShortNoteNotice{
		ProjectId:    req.ProjectId,
		MemberUserId: sessionItem.UserId,
	})
	return ret.(*short_note_api.AddResponse), nil
}

func (apiImpl *ShortNoteApiImpl) Remove(ctx context.Context, req *short_note_api.RemoveRequest) (*short_note_api.RemoveResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &short_note_api.RemoveResponse{
			Code:   short_note_api.RemoveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &short_note_api.RemoveResponse{
			Code:   short_note_api.RemoveResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &short_note_api.RemoveResponse{
			Code:   short_note_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := short_note_dao.ShortNoteDao.Exist(ctx, sessionItem.UserId, req.ProjectId, uint32(req.ShortNoteType), req.TargetId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &short_note_api.RemoveResponse{
			Code: short_note_api.RemoveResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = short_note_dao.ShortNoteDao.Remove(sessCtx, sessionItem.UserId, req.ProjectId, uint32(req.ShortNoteType), req.TargetId)
		if err != nil {
			return nil, err
		}
		return &short_note_api.RemoveResponse{
			Code: short_note_api.RemoveResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateShortNoteNotice{
		ProjectId:    req.ProjectId,
		MemberUserId: sessionItem.UserId,
	})
	return ret.(*short_note_api.RemoveResponse), nil
}

func (apiImpl *ShortNoteApiImpl) ListMy(ctx context.Context, req *short_note_api.ListMyRequest) (*short_note_api.ListMyResponse, error) {
	emptyList := []*short_note_api.ShortNote{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &short_note_api.ListMyResponse{
			Code:          short_note_api.ListMyResponse_CODE_WRONG_SESSION,
			ErrMsg:        "会话不存在",
			ShortNoteList: emptyList,
		}, nil
	}

	projectIdList, err := project_dao.MemberInfoDao.ListProjectByMember(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	shortNoteItemList, err := short_note_dao.ShortNoteDao.List(ctx, []string{sessionItem.UserId}, projectIdList)
	if err != nil {
		return nil, err
	}
	issueTitleMap, docTitlemap, err := apiImpl.getTitleMap(ctx, shortNoteItemList)
	if err != nil {
		return nil, err
	}

	projectItemList, err := project_dao.ProjectInfoDao.ListById(ctx, projectIdList, false, false)
	if err != nil {
		return nil, err
	}
	projectNameMap := map[string]string{}
	for _, projectItem := range projectItemList {
		projectNameMap[projectItem.ProjectId] = projectItem.BasicInfo.ProjectName
	}

	shortNoteList := []*short_note_api.ShortNote{}
	for _, shortNoteItem := range shortNoteItemList {
		title := ""
		if shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_TASK) || shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_BUG) {
			title = issueTitleMap[shortNoteItem.TargetId]
		} else if shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_DOC) {
			title = docTitlemap[shortNoteItem.TargetId]
		}
		shortNoteList = append(shortNoteList, shortNoteItem.ToShortNote(title, projectNameMap[shortNoteItem.ProjectId]))
	}
	return &short_note_api.ListMyResponse{
		Code:          short_note_api.ListMyResponse_CODE_OK,
		ShortNoteList: shortNoteList,
	}, nil
}

func (apiImpl *ShortNoteApiImpl) getTitleMap(ctx context.Context, shortNoteItemList []*short_note_dao.ShortNoteDbItem) (map[string]string, map[string]string, error) {
	issueIdList := []string{}
	docIdList := []string{}
	for _, shortNoteItem := range shortNoteItemList {
		if shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_TASK) || shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_BUG) {
			issueIdList = append(issueIdList, shortNoteItem.TargetId)
		} else if shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_DOC) {
			docIdList = append(docIdList, shortNoteItem.TargetId)
		}
	}
	//列出issue
	issueTitleMap := map[string]string{}
	issueItemList, err := issue_dao.IssueDao.ListByIdOnly(ctx, issueIdList)
	if err != nil {
		return nil, nil, err
	}
	for _, issueItem := range issueItemList {
		issueTitleMap[issueItem.IssueId] = issueItem.BasicInfo.Title
	}
	//列出doc
	docTitleMap := map[string]string{}
	entryItemList, err := project_entry_dao.EntryDao.ListById(ctx, docIdList)
	if err != nil {
		return nil, nil, err
	}
	for _, entryItem := range entryItemList {
		docTitleMap[entryItem.EntryId] = entryItem.EntryTitle
	}
	return issueTitleMap, docTitleMap, nil
}

func (apiImpl *ShortNoteApiImpl) ListByMember(ctx context.Context, req *short_note_api.ListByMemberRequest) (*short_note_api.ListByMemberResponse, error) {
	emptyList := []*short_note_api.ShortNote{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &short_note_api.ListByMemberResponse{
			Code:          short_note_api.ListByMemberResponse_CODE_WRONG_SESSION,
			ErrMsg:        "会话不存在",
			ShortNoteList: emptyList,
		}, nil
	}
	//检测权限
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &short_note_api.ListByMemberResponse{
			Code:          short_note_api.ListByMemberResponse_CODE_NO_PROJECT,
			ErrMsg:        "项目不存在",
			ShortNoteList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &short_note_api.ListByMemberResponse{
			Code:          short_note_api.ListByMemberResponse_CODE_NO_PERMISSION,
			ErrMsg:        "没有权限",
			ShortNoteList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}
	exist, err := project_dao.MemberInfoDao.Exist(ctx, req.ProjectId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &short_note_api.ListByMemberResponse{
			Code:          short_note_api.ListByMemberResponse_CODE_NO_MEMBER,
			ErrMsg:        "目标成员不存在",
			ShortNoteList: emptyList,
		}, nil
	}

	shortNoteItemList, err := short_note_dao.ShortNoteDao.List(ctx, []string{req.MemberUserId}, []string{req.ProjectId})
	if err != nil {
		return nil, err
	}
	issueTitleMap, docTitlemap, err := apiImpl.getTitleMap(ctx, shortNoteItemList)
	if err != nil {
		return nil, err
	}

	shortNoteList := []*short_note_api.ShortNote{}
	for _, shortNoteItem := range shortNoteItemList {
		title := ""
		if shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_TASK) || shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_BUG) {
			title = issueTitleMap[shortNoteItem.TargetId]
		} else if shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_DOC) {
			title = docTitlemap[shortNoteItem.TargetId]
		}
		shortNoteList = append(shortNoteList, shortNoteItem.ToShortNote(title, projectItem.BasicInfo.ProjectName))
	}

	return &short_note_api.ListByMemberResponse{
		Code:          short_note_api.ListByMemberResponse_CODE_OK,
		ShortNoteList: shortNoteList,
	}, nil
}

func (apiImpl *ShortNoteApiImpl) ListByProject(ctx context.Context, req *short_note_api.ListByProjectRequest) (*short_note_api.ListByProjectResponse, error) {
	emptyList := []*short_note_api.ShortNote{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &short_note_api.ListByProjectResponse{
			Code:          short_note_api.ListByProjectResponse_CODE_WRONG_SESSION,
			ErrMsg:        "会话不存在",
			ShortNoteList: emptyList,
		}, nil
	}
	//检测权限
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &short_note_api.ListByProjectResponse{
			Code:          short_note_api.ListByProjectResponse_CODE_NO_PROJECT,
			ErrMsg:        "项目不存在",
			ShortNoteList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &short_note_api.ListByProjectResponse{
			Code:          short_note_api.ListByProjectResponse_CODE_NO_PERMISSION,
			ErrMsg:        "没有权限",
			ShortNoteList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	memberUserIdList, err := project_dao.MemberInfoDao.ListMemberId(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}
	shortNoteItemList, err := short_note_dao.ShortNoteDao.List(ctx, memberUserIdList, []string{req.ProjectId})
	if err != nil {
		return nil, err
	}
	issueTitleMap, docTitlemap, err := apiImpl.getTitleMap(ctx, shortNoteItemList)
	if err != nil {
		return nil, err
	}

	shortNoteList := []*short_note_api.ShortNote{}
	for _, shortNoteItem := range shortNoteItemList {
		title := ""
		if shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_TASK) || shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_BUG) {
			title = issueTitleMap[shortNoteItem.TargetId]
		} else if shortNoteItem.ShortNoteType == uint32(short_note_api.SHORT_NOTE_TYPE_SHORT_NOTE_DOC) {
			title = docTitlemap[shortNoteItem.TargetId]
		}
		shortNoteList = append(shortNoteList, shortNoteItem.ToShortNote(title, projectItem.BasicInfo.ProjectName))
	}

	return &short_note_api.ListByProjectResponse{
		Code:          short_note_api.ListByProjectResponse_CODE_OK,
		ShortNoteList: shortNoteList,
	}, nil
}
